#include "formslaveparam.h"
#include "ui_formslaveparam.h"
#include "dcsproto/proto.h"

#include <QDebug>
#include <cmath>
#include <QThread>
#include <QMessageBox>
#include <global.h>

FormSlaveParam::FormSlaveParam(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::FormSlaveParam)
{
    ui->setupUi(this);
    setWindowFlags(windowFlags() | Qt::Dialog);
    setWindowModality(Qt::ApplicationModal);
    setAttribute(Qt::WA_DeleteOnClose);

    mDbopt = new DCSDbOperator();
    quint8 iface;
    if (!DCSDbOperator::getMasterParameterInterface(iface))
    {
        qDebug() << "db get interface error,set to default";
        iface = UDP_IFACE_EN_WAN;
    }

    if (iface == UDP_IFACE_EN_WAN)
    {
        mUdp = new UdpWorker(INTERFACE_WAN_NAME);
    }
    else
    {
        mUdp = new UdpWorker(INTERFACE_LAN_NAME);
    }

    numberkeyboard = new DialogVKB(this);
    //将所有lineedit信号都和软件盘界面显示关联
    connect(ui->lineEditGamma, &VKB_lineEdit::send_show, this, &FormSlaveParam::show_numberkeyboard_ui);
    connect(numberkeyboard, &DialogVKB::sendMessage, this, &FormSlaveParam::confirmString);

    connect(mUdp, &UdpWorker::dataRecvdBytes, this, &FormSlaveParam::on_dataRecved);

    connect(ui->comboBoxChipType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            this, &FormSlaveParam::onChipTypeIndexChanged);

    connect(ui->comboBoxChannelNum, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
            this, &FormSlaveParam::onChannelChanged);

    connect(ui->comboBoxClockFreq, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
            this, &FormSlaveParam::onClockFreqChanged);

    connect(ui->comboBoxClockDurationRate, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            this, &FormSlaveParam::onDutyRateChanged);

    connect(ui->comboBoxColorNum, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            this, &FormSlaveParam::onColorChanged);

    connect(ui->lineEditGamma, &QLineEdit::textChanged, this, &FormSlaveParam::onGammaChanged);

    int value = 100;
    ui->horizontalSliderBrightness->setSliderPosition(value);
    ui->horizontalSliderBrightness1->setSliderPosition(value);
    ui->horizontalSliderBrightness2->setSliderPosition(value);
    ui->horizontalSliderBrightness3->setSliderPosition(value);
    ui->horizontalSliderBrightness4->setSliderPosition(value);

    ui->labelBv->setNum(value);
    ui->labelBv1->setNum(value);
    ui->labelBv2->setNum(value);
    ui->labelBv3->setNum(value);
    ui->labelBv4->setNum(value);

    qDebug() << "[FormSlaveParam] \t Constructor";
}

FormSlaveParam::~FormSlaveParam()
{
    delete ui;
    delete mUdp;
    delete numberkeyboard;
    delete mDbopt;
    qDebug() << "[FormSlaveParam] \t Destructor";
}

int FormSlaveParam::getChipIndexByChipType(quint16 chiptype)
{
    for (int i = 0; i < Ui::TlbSize; i++)
    {
        if (chiptype == Ui::ChipIDTable[i])
        {
            return i;
        }
    }

    //默认返回 UCS512C 类型
    return 2;
}

quint16 FormSlaveParam::getChipTypeByChipIndex(int chipid)
{
    Q_ASSERT((chipid < Ui::TlbSize) && (chipid >= 0));

    return Ui::ChipIDTable[chipid];
}

/**
 * @brief FormSlaveParam::fillGamaData
 *          根据gamma值gamaVal生成gamma表到pAddr
 * @param pAddr
 * @param gamaVal
 */
void FormSlaveParam::fillGamaData(unsigned short *pAddr, int gammaVal) const
{
    int iSel = 16 - mGrayLvl;

//    if ((mCurIC.chipIndex >= 4) && (mCurIC.chipIndex <= 8))
//    {
//        iSel = 8;
//    }

    int val = (int) pow(2, (16 - iSel));
    for (int i = 0; i <= 255; i++)
    {
        auto d1 = (double) (i / 255.0);
        auto d2 = (double) (gammaVal / 10.0);
        double d3 = ((val - 1) * pow(d1, d2));
        auto uCheck = (unsigned int) round(d3);
        *(pAddr + i) = uCheck;
    }
}

void FormSlaveParam::show_numberkeyboard_ui(const QString &data)
{
    lineEdit_object = sender()->objectName();//获得调用软件盘的部件的名称
    numberkeyboard->setInputdata(data);
    numberkeyboard->show();
}

void FormSlaveParam::confirmString(const QString &gemfield)
{
    //判断应该将信息写入哪一个输入框
    if (lineEdit_object == ui->lineEditGamma->objectName())
    {
        ui->lineEditGamma->setText(gemfield);
    }
}

void FormSlaveParam::on_pushButtonReturn_clicked()
{
    this->close();
}

void FormSlaveParam::on_pushButtonRead_clicked()
{
    slaveParamReadWin = new DialogSlaveParamRead(this);
    connect(slaveParamReadWin, &DialogSlaveParamRead::accepted, this, &FormSlaveParam::on_readDialogCommit);
    slaveParamReadWin->show();
}

void FormSlaveParam::on_readDialogCommit()
{
    qDebug() << "commit accept read dialog";

    unsigned short inputid = slaveParamReadWin->getInputValue();
    qDebug() << "input value:" << inputid;
    if (inputid > 0)
    {
        char buf[60];
        memset(buf, 0x0, 60);
        struct slave_conf_read_pdu pdu{};
        pdu.conf_id = SLAVE_CONF_READ_PARAM;
        aklt_proto_encode((unsigned char *) buf, TYP_SLAVE_CONF_READ, CMD_SLAVE_CONF_READ, inputid,
                          (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);

        mUdp->dataSend(buf, 60);
    }
}

void FormSlaveParam::on_writeDialogCommit()
{
    int sid, eid;

    slaveParamWriteWin->getInputValue(sid, eid);

    qDebug() << "start id:" << sid << "end id:" << eid;

    //填充分控参数PDU
    struct slave_hardware_param_pdu pdu{};
    memset(&pdu, 0x0, sizeof(pdu));

    pdu.pkgnum = 2;
    pdu.pkgno = 1;
    pdu.pkgsize = 0x0029;
    pdu.chiptype = mCurIC.chipTypeId;
    pdu.port_ch_num = mChannelNum;
    pdu.gray_lvl = mGrayLvl;
    pdu.clock_freq = mClockFreq;
    pdu.clock_freq_read = mClockFreqRead;
    pdu.ch0_finetune = mCh0FineTune;
    pdu.dutyrate = mDutyRate;
    pdu.gray_filter = mGrayFilter;
    pdu.color_num = mColorNum;
    pdu.oe = mOe;
    pdu.gamma_tune_type = mGammaTuneType;
    pdu.gamma[0] = mGamma[0];
    pdu.gamma[1] = mGamma[1];
    pdu.gamma[2] = mGamma[2];
    pdu.gamma[3] = mGamma[3];
    pdu.brightness_tune_type = mBrightnessTuneType;
    pdu.brightness[0] = mBrightness[0];
    pdu.brightness[1] = mBrightness[1];
    pdu.brightness[2] = mBrightness[2];
    pdu.brightness[3] = mBrightness[3];
    pdu.reflesh_type = mRefleshType;
    pdu.reflesh_value = mRefleshValue;
    pdu.current_gain[0] = mCurrentGain[0];
    pdu.current_gain[1] = mCurrentGain[1];
    pdu.current_gain[2] = mCurrentGain[2];
    pdu.current_gain[3] = mCurrentGain[3];
    pdu.output_inverse = mOutputInverse;
    pdu.addr_pin_lvl = mAddrPinLvl;
    pdu.led_hold = mLedHold;

    //填充gamma表PDU
    struct slave_gammatable_pdu gammatablPdu{};
    memset(&gammatablPdu, 0x0, sizeof(gammatablPdu));

    gammatablPdu.pkgnum = 2;
    gammatablPdu.pkgno = 2;
    gammatablPdu.pkgsize = 0x400;
    //m620仅使用统一的gamma表
    fillGamaData(gammatablPdu.gammatabl[0], mGamma[0]);

    //填充确认PDU
    struct slave_conf_read_pdu checkPdu{};
    checkPdu.conf_id = SLAVE_CONF_PARAM_CHECK;

    char buf[60];
    char gammatablebuf[1048];

    for (int i = sid; i <= eid; i++)
    {
        //发送分控参数
        memset(buf, 0x0, 60);
        aklt_proto_encode((unsigned char *) buf, TYP_SLAVE_CONF_WRITE, CMD_SLAVE_CONF_WRITE, i,
                          (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);
        mUdp->dataSend(buf, 60);
        QThread::msleep(500);   //连续发送命令时需要加入一定延时，这里涉及FPGA保存数据时读写flash操作，需要一定处理时间

        //发送gamma表
        memset(gammatablebuf, 0x0, 1048);
        int ret = aklt_proto_encode((unsigned char *) gammatablebuf, TYP_SLAVE_CONF_WRITE, CMD_SLAVE_CONF_WRITE, i,
                                    (unsigned char *) &gammatablPdu, sizeof(gammatablPdu), SLAVE_UNICAST);
        mUdp->dataSend(gammatablebuf, ret);

        QThread::msleep(500);
        //发送分控参数确认命令
        memset(buf, 0x0, 60);
        aklt_proto_encode((unsigned char *) buf, TYP_SLAVE_CONF_READ, CMD_SLAVE_CONF_READ, i,
                          (unsigned char *) &checkPdu, sizeof(checkPdu), SLAVE_UNICAST);
        mUdp->dataSend(buf, 60);

        if (mUdp->waitForRecvBytes(200))
        {
            qDebug() << "wait for read";
        }
        else
        {
            qDebug() << "timeout";
        }

        QThread::msleep(200);
    }
}

void FormSlaveParam::on_pushButtonWrite_clicked()
{
    slaveParamWriteWin = new DialogSlaveParamWrite(this);
    connect(slaveParamWriteWin, SIGNAL(accepted()), this, SLOT(on_writeDialogCommit()));
    slaveParamWriteWin->show();
}

void FormSlaveParam::on_horizontalSliderBrightness_valueChanged(int value)
{
    quint16 bvalue;

    ui->horizontalSliderBrightness1->setSliderPosition(value);
    ui->horizontalSliderBrightness2->setSliderPosition(value);
    ui->horizontalSliderBrightness3->setSliderPosition(value);
    ui->horizontalSliderBrightness4->setSliderPosition(value);
    ui->labelBv->setNum(value);
    ui->labelBv1->setNum(value);
    ui->labelBv2->setNum(value);
    ui->labelBv3->setNum(value);
    ui->labelBv4->setNum(value);

    bvalue = (value << 8) / 100;
    mBrightness[0] = bvalue;
    mBrightness[1] = bvalue;
    mBrightness[2] = bvalue;
    mBrightness[3] = bvalue;
}

void FormSlaveParam::on_horizontalSliderBrightness1_valueChanged(int value)
{
    quint16 bvalue;

    ui->labelBv1->setNum(value);
    bvalue = (value << 8) / 100;
    mBrightness[0] = bvalue;
}

void FormSlaveParam::on_horizontalSliderBrightness2_valueChanged(int value)
{
    quint16 bvalue;

    ui->labelBv2->setNum(value);
    bvalue = (value << 8) / 100;
    mBrightness[1] = bvalue;
}

void FormSlaveParam::on_horizontalSliderBrightness3_valueChanged(int value)
{
    quint16 bvalue;
    ui->labelBv3->setNum(value);
    bvalue = (value << 8) / 100;
    mBrightness[2] = bvalue;
}

void FormSlaveParam::on_horizontalSliderBrightness4_valueChanged(int value)
{
    quint16 bvalue;

    ui->labelBv4->setNum(value);
    bvalue = (value << 8) / 100;
    mBrightness[3] = bvalue;
}

void FormSlaveParam::on_dataRecved(QByteArray &data)
{
    struct akltproto aklt{};
    aklt_proto_decode(&aklt, (unsigned char *) (data.data()), data.size());

    qDebug() << "aklt.type:" << aklt.type << "aklt.cmd:" << aklt.cmd;

    //分控硬件参数回读回复
    if (aklt.type == TYP_SLAVE_CONF_ACK && aklt.cmd == CMD_SLAVE_READ_PARAM_ACK)
    {
        auto *ack = (struct slave_hardware_param_pdu *) (aklt.data);
        mCurIC.chipTypeId = ack->chiptype;
        mChannelNum = ack->port_ch_num;
        mGrayLvl = ack->gray_lvl;
        mClockFreq = 8000 / ack->clock_freq_read;
        mClockFreqRead = ack->clock_freq_read;
        mCh0FineTune = ack->ch0_finetune;
        mDutyRate = ack->dutyrate;
        mGrayFilter = ack->gray_filter;
        mColorNum = ack->color_num;
        mOe = ack->oe;
        mGammaTuneType = ack->gamma_tune_type;
        mGamma[0] = ack->gamma[0];
        mGamma[1] = ack->gamma[1];
        mGamma[2] = ack->gamma[2];
        mGamma[3] = ack->gamma[3];
        mBrightnessTuneType = ack->brightness_tune_type;
        mBrightness[0] = ack->brightness[0];
        mBrightness[1] = ack->brightness[1];
        mBrightness[2] = ack->brightness[2];
        mBrightness[3] = ack->brightness[3];
        mRefleshType = ack->reflesh_type;
        mRefleshValue = ack->reflesh_value;
        mCurrentGain[0] = ack->current_gain[0];
        mCurrentGain[1] = ack->current_gain[1];
        mCurrentGain[2] = ack->current_gain[2];
        mCurrentGain[3] = ack->current_gain[3];
        mOutputInverse = ack->output_inverse;
        mAddrPinLvl = ack->addr_pin_lvl;
        mLedHold = ack->led_hold;

        //更新页面显示
        ui->comboBoxChannelNum->setCurrentText(QString("").sprintf("%d", ack->port_ch_num));
        ui->comboBoxColorNum->setCurrentIndex(ack->color_num);
        ui->comboBoxClockFreq->setCurrentText(QString("").sprintf("%3.2f", ack->clock_freq_read / 100.0));
        ui->comboBoxClockDurationRate->setCurrentText(QString("").sprintf("%2.0f", (ack->dutyrate + 1) * 100 / 256.0));
        ui->lineEditGamma->setText(QString("").sprintf("%1.1f", ack->gamma[0] / 10.0));

        if (ack->brightness_tune_type == 0)//整体调整
        {
            ui->horizontalSliderBrightness->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness1->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness2->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness3->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness4->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
        }
        else//分别调整
        {
            ui->horizontalSliderBrightness1->setSliderPosition((ack->brightness[0] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness2->setSliderPosition((ack->brightness[1] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness3->setSliderPosition((ack->brightness[2] + 1) * 100 / 256.0);
            ui->horizontalSliderBrightness4->setSliderPosition((ack->brightness[3] + 1) * 100 / 256.0);
        }

        ui->comboBoxChipType->setCurrentIndex(getChipIndexByChipType(ack->chiptype));

        //读取过参数，才允许写分控参数，因为有些参数在ui界面上未展示，无法设置，所以依赖读取来初始化
        ui->pushButtonWrite->setEnabled(true);
    }
    else if (aklt.type == TYP_SLAVE_CONF_ACK && aklt.cmd == CMD_SLAVE_PARAM_CONF_ACK)
    {
        //分控硬件参数写入确认回复
        auto *ack = (struct slave_conf_ack_pdu *) (aklt.data);
        qDebug() << "finished:" << ack->finished;
    }

    delete aklt.data;
}

void FormSlaveParam::onChipTypeIndexChanged(int index)
{
    mCurIC.chipIndex = index;
    mCurIC.chipTypeId = getChipTypeByChipIndex(index);;

    qDebug() << "chip index changed to:" << index << "chip type changed to:" << hex << mCurIC.chipTypeId;
}

void FormSlaveParam::onChannelChanged(const QString &text)
{
    mChannelNum = text.toUInt();
    if (mChannelNum > MAX_CHANNEL_NUM)
    {
        qDebug() << "channel num to large";
        mChannelNum = DEFAULT_CHANNEL_NUM;
    }

    qDebug() << "channel num set to:" << mChannelNum;
}

void FormSlaveParam::onClockFreqChanged(const QString &text)
{
    float originalClkFreq;

    originalClkFreq = text.toFloat();
    if (originalClkFreq > MAX_CLKFREQ_VALUE)
    {
        originalClkFreq = DEFAULT_CLKFREQ_VALUE;
    }

    mClockFreq = 80 / originalClkFreq;
    mClockFreqRead = originalClkFreq * 100;

    qDebug() << "clock freq set to:" << mClockFreq;
}

void FormSlaveParam::onDutyRateChanged(int index)
{
    mDutyRate = percentConvert2Dutyrate((index + 1) * 10);

    qDebug() << "duty rate set to:0x" << hex << mDutyRate;
}

/**
 * LED颜色数设置槽函数，0：三色 1：四色
 * @param index
 */
void FormSlaveParam::onColorChanged(int index)
{
    Q_ASSERT(index == 0 || index == 1);

    mColorNum = index;

    qDebug() << "color num set to:" << mColorNum;
}

/**
 * gamma值设置槽函数
 * @param text
 */
void FormSlaveParam::onGammaChanged(const QString &text)
{
    float originalGammaValue;   //原始的gamma值，浮点类型
    quint16 GammaValue;         //数据交互时gamma值放大1000倍

    originalGammaValue = text.toFloat();

    //gamma值最大为8.8
    if (originalGammaValue > MAX_GAMMA_VALUE)
    {
//        QMessageBox::information(this, tr("提示"), tr("Gamma值不能大于8.8"));
        originalGammaValue = DEFAULT_GAMMA_VALUE;
        ui->lineEditGamma->setText("2.2");
    }

    GammaValue = originalGammaValue * 10;

    //使用统一gamma表
    mGammaTuneType = 0;
    mGamma[0] = GammaValue;
    mGamma[1] = GammaValue;
    mGamma[2] = GammaValue;
    mGamma[3] = GammaValue;

    qDebug() << "original gamma:" << originalGammaValue;
    qDebug() << "gamma set to:" << mGamma[0];
}

quint8 FormSlaveParam::dutyrateConvert2Percent(quint8 value)
{
    for (int i = 0; i < sizeof(Ui::mClkFreqConvertTable) / sizeof(Ui::mClkFreqConvertTable[0]); ++i)
    {
        if (value == Ui::mClkFreqConvertTable[i])
        {
            return (i + 1) * 10;
        }
    }

    //默认返回50%
    return 50;
}

quint8 FormSlaveParam::percentConvert2Dutyrate(quint8 percent)
{
    Q_ASSERT(percent >= 10 && percent <= 90);
    quint8 index;

    index = percent / 10 - 1;

    return Ui::mClkFreqConvertTable[index];
}
